#ifndef CLUSNET_NET_UDPCLIENT_H
#define CLUSNET_NET_UDPCLIENT_H

#include <boost/asio.hpp>
#include <boost/array.hpp>
#include <string>
#include "UdpSession.h"
#include "UdpDataPacket.h"
#include "Callbacks.h"

namespace clusnet
{
namespace net
{

class UdpClient final : public std::enable_shared_from_this<UdpClient>
{
    public:
        UdpClient(boost::asio::io_context& io, char const* host, char const* port, boost::asio::ip::udp::resolver::protocol_type const& proto = boost::asio::ip::udp::v4());
        ~UdpClient();
        UdpClient(UdpClient const&) = delete;
        UdpClient& operator= (UdpClient const&) = delete;

    public:
        void setWriteCompleteCallback(UdpWriteCompleteCallback const& cb) { writeCallback_ = cb; }
        void setMessageCallback(UdpMessageCallback const& cb) { messageCallback_ = cb; }

    public:
        void safeAsyncWrite(UdpDataPacketPtr const&);
        void safeClose();
        void safeStartReceive();

    private:
        void handleWriteComplete(UdpSessionPtr&, UdpDataPacketPtr const&);

    private:
        boost::asio::io_context&        io_;
        boost::asio::io_context::strand strand_;
        boost::asio::ip::udp::socket    socket_;
        boost::asio::ip::udp::endpoint  remoteEndpoint_; 
        UdpSessionPtr                   session_;
        bool                            close_;
        bool                            waitRecv_;
        UdpWriteCompleteCallback        writeCallback_;
        UdpMessageCallback              messageCallback_;
        boost::array<char, UdpDataPacket::maxLength()>              recvBuffer_;
        boost::asio::ip::udp::endpoint  recvEndpoint_;
};
}
}

#endif
